import org.jcsp.lang.*;

 class Philosophers implements CSProcess {

  private final int nPhilosophers;

  private final PhilReport philReport;
  private final ForkReport forkReport;
  private final ChannelOutputInt securityReport;


  public Philosophers (int nPhilosophers, 
                       PhilReport philReport,
                       ForkReport forkReport,
                       ChannelOutputInt securityReport
                                    
                                    ) {
    this.nPhilosophers = nPhilosophers;
    this.philReport = philReport;
    this.forkReport = forkReport;
    this.securityReport = securityReport;
  }

  public void run () {

    final One2OneChannelInt[] left = Channel.one2oneIntArray (nPhilosophers);
    final One2OneChannelInt[] right = Channel.one2oneIntArray (nPhilosophers);

    final Any2OneChannelInt down = Channel.any2oneInt ();
    final Any2OneChannelInt up = Channel.any2oneInt ();

    final Fork[] fork = new Fork[nPhilosophers];
    for (int i = 0; i < nPhilosophers; i++) {
      fork[i] = new Fork (nPhilosophers, i,
                          left[i].in (), right[(i + 1)%nPhilosophers].in (), forkReport);
    }

    final Philosopher[] phil = new Philosopher[nPhilosophers];
    for (int i = 0; i < nPhilosophers; i++) {
      phil[i] = new Philosopher (i, left[i].out (), right[i].out (), down.out (), up.out (), philReport);
    }

    new Parallel (
      new CSProcess[] {
        new Parallel (phil),
        new Parallel (fork),
        new Security (down.in (), up.in (), securityReport, nPhilosophers - 1)
      }
    ).run ();
  }
}
